﻿#region MIT License
/*
 * Copyright (c) 2010 Michael Gray
 * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 * 
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 
*/
#endregion

using System;
using System.Runtime.InteropServices;

namespace MPCLI
{
    public static class IntegerCore
    {
        #region Constant Fields

        private const string LibraryName = "gmp.dll";

        #endregion

        #region Static Fields

        public static readonly int StateSize = (sizeof(int) * 2) + IntPtr.Size;

        #endregion

        #region Initialization

        [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "__gmpz_init", ExactSpelling = true)]
        public static extern void Initialize(
            [In, Out, MarshalAs(UnmanagedType.Struct)] ref IntegerState state);

        [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "__gmpz_init_set", ExactSpelling = true)]
        public static extern void Initialize(
            [In, Out, MarshalAs(UnmanagedType.Struct)] ref IntegerState result,
            [In, MarshalAs(UnmanagedType.Struct)] ref IntegerState value);

        [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "__gmpz_init_set_si", ExactSpelling = true)]
        public static extern void Initialize(
            [In, Out, MarshalAs(UnmanagedType.Struct)] ref IntegerState result,
            [In, MarshalAs(UnmanagedType.I4)] int value);

        [CLSCompliant(false)]
        [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "__gmpz_init_set_ui", ExactSpelling = true)]
        public static extern void Initialize(
            [In, Out, MarshalAs(UnmanagedType.Struct)] ref IntegerState result,
            [In, MarshalAs(UnmanagedType.I4)] uint value);

        [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "__gmpz_init_set_str", ExactSpelling = true)]
        public static extern int Initialize(
            [In, Out, MarshalAs(UnmanagedType.Struct)] ref IntegerState state,
            [In, MarshalAs(UnmanagedType.LPStr)] string value,
            [In, MarshalAs(UnmanagedType.I4)] int radix);

        #endregion

        #region Memory Management

        [CLSCompliant(false)]
        [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "__gmpz_init2", ExactSpelling = true)]
        public static extern void Allocate(
            [In, Out, MarshalAs(UnmanagedType.Struct)] ref IntegerState state,
            [In, MarshalAs(UnmanagedType.U4)] uint size);

        [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "__gmpz_clear", ExactSpelling = true)]
        public static extern void Free(
            [In, Out, MarshalAs(UnmanagedType.Struct)] ref IntegerState state);

        #endregion

        #region Conversion

        [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "__gmpz_get_str", ExactSpelling = true)]
        public static extern string GetString(
            [In, MarshalAs(UnmanagedType.SysInt)] IntPtr buffer,
            [In, MarshalAs(UnmanagedType.I4)] int radix,
            [In, MarshalAs(UnmanagedType.Struct)] ref IntegerState operand);

        #endregion

        #region Arithmetic

        [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "__gmpz_add", ExactSpelling = true)]
        public static extern void Add(
            [In, Out, MarshalAs(UnmanagedType.Struct)] ref IntegerState result,
            [In, MarshalAs(UnmanagedType.Struct)] ref IntegerState first,
            [In, MarshalAs(UnmanagedType.Struct)] ref IntegerState second);

        [CLSCompliant(false)]
        [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "__gmpz_add_ui", ExactSpelling = true)]
        public static extern void Add(
            [In, Out, MarshalAs(UnmanagedType.Struct)] ref IntegerState result,
            [In, MarshalAs(UnmanagedType.Struct)] ref IntegerState first,
            [In, MarshalAs(UnmanagedType.U4)] uint second);

        [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "__gmpz_sub", ExactSpelling = true)]
        public static extern void Subtract(
            [In, Out, MarshalAs(UnmanagedType.Struct)] ref IntegerState result,
            [In, MarshalAs(UnmanagedType.Struct)] ref IntegerState first,
            [In, MarshalAs(UnmanagedType.Struct)] ref IntegerState second);

        [CLSCompliant(false)]
        [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "__gmpz_sub_ui", ExactSpelling = true)]
        public static extern void Subtract(
            [In, Out, MarshalAs(UnmanagedType.Struct)] ref IntegerState result,
            [In, MarshalAs(UnmanagedType.Struct)] ref IntegerState first,
            [In, MarshalAs(UnmanagedType.U4)] uint second);

        [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "__gmpz_mul", ExactSpelling = true)]
        public static extern void Multiply(
            [In, Out, MarshalAs(UnmanagedType.Struct)] ref IntegerState result,
            [In, MarshalAs(UnmanagedType.Struct)] ref IntegerState first,
            [In, MarshalAs(UnmanagedType.Struct)] ref IntegerState second);

        [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "__gmpz_mul_si", ExactSpelling = true)]
        public static extern void Multiply(
            [In, Out, MarshalAs(UnmanagedType.Struct)] ref IntegerState result,
            [In, MarshalAs(UnmanagedType.Struct)] ref IntegerState first,
            [In, MarshalAs(UnmanagedType.I4)] int second);

        [CLSCompliant(false)]
        [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "__gmpz_mul_ui", ExactSpelling = true)]
        public static extern void Multiply(
            [In, Out, MarshalAs(UnmanagedType.Struct)] ref IntegerState result,
            [In, MarshalAs(UnmanagedType.Struct)] ref IntegerState first,
            [In, MarshalAs(UnmanagedType.U4)] uint second);

        [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "__gmpz_tdiv_q", ExactSpelling = true)]
        public static extern void Divide(
            [In, Out, MarshalAs(UnmanagedType.Struct)] ref IntegerState result,
            [In, MarshalAs(UnmanagedType.Struct)] ref IntegerState first,
            [In, MarshalAs(UnmanagedType.Struct)] ref IntegerState second);

        [CLSCompliant(false)]
        [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "__gmpz_tdiv_q_ui", ExactSpelling = true)]
        public static extern uint Divide(
            [In, Out, MarshalAs(UnmanagedType.Struct)] ref IntegerState result,
            [In, MarshalAs(UnmanagedType.Struct)] ref IntegerState first,
            [In, MarshalAs(UnmanagedType.U4)] uint second);

        [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "__gmpz_mod", ExactSpelling = true)]
        public static extern void Modulus(
            [In, Out, MarshalAs(UnmanagedType.Struct)] ref IntegerState result,
            [In, MarshalAs(UnmanagedType.Struct)] ref IntegerState first,
            [In, MarshalAs(UnmanagedType.Struct)] ref IntegerState second);

        [CLSCompliant(false)]
        [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "__gmpz_fdiv_ui", ExactSpelling = true)]
        public static extern uint Modulus(
            [In, MarshalAs(UnmanagedType.Struct)] ref IntegerState first,
            [In, MarshalAs(UnmanagedType.U4)] uint second);

        [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "__gmpz_powm", ExactSpelling = true)]
        public static extern void ModularExponent(
            [In, Out, MarshalAs(UnmanagedType.Struct)] ref IntegerState result,
            [In, MarshalAs(UnmanagedType.Struct)] ref IntegerState radix,
            [In, MarshalAs(UnmanagedType.Struct)] ref IntegerState exponent,
            [In, MarshalAs(UnmanagedType.Struct)] ref IntegerState modulus);

        [CLSCompliant(false)]
        [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "__gmpz_powm_ui", ExactSpelling = true)]
        public static extern void ModularExponent(
            [In, Out, MarshalAs(UnmanagedType.Struct)] ref IntegerState result,
            [In, MarshalAs(UnmanagedType.Struct)] ref IntegerState radix,
            [In, MarshalAs(UnmanagedType.U4)] uint exponent,
            [In, MarshalAs(UnmanagedType.Struct)] ref IntegerState modulus);

        [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "__gmpz_powm_sec", ExactSpelling = true)]
        public static extern void SecureModularExponent(
            [In, Out, MarshalAs(UnmanagedType.Struct)] ref IntegerState result,
            [In, MarshalAs(UnmanagedType.Struct)] ref IntegerState radix,
            [In, MarshalAs(UnmanagedType.Struct)] ref IntegerState exponent,
            [In, MarshalAs(UnmanagedType.Struct)] ref IntegerState modulus);

        [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "__gmpz_pow_ui", ExactSpelling = true)]
        public static extern void Exponent(
            [In, Out, MarshalAs(UnmanagedType.Struct)] ref IntegerState result,
            [In, MarshalAs(UnmanagedType.Struct)] ref IntegerState radix,
            [In, MarshalAs(UnmanagedType.U4)] uint exponent);

        #endregion

        #region Number Theoretic

        [CLSCompliant(false)]
        [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "__gmpz_fac_ui", ExactSpelling = true)]
        public static extern void Factorial(
            [In, Out, MarshalAs(UnmanagedType.Struct)] ref IntegerState result,
            [In, MarshalAs(UnmanagedType.U4)] uint operand);

        [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "__gmpz_gcd", ExactSpelling = true)]
        public static extern void GCD(
            [In, Out, MarshalAs(UnmanagedType.Struct)] ref IntegerState result,
            [In, MarshalAs(UnmanagedType.Struct)] ref IntegerState first,
            [In, MarshalAs(UnmanagedType.Struct)] ref IntegerState second);

        [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "__gmpz_nextprime", ExactSpelling = true)]
        public static extern void GetNextPrime(
            [In, Out, MarshalAs(UnmanagedType.Struct)] ref IntegerState result,
            [In, MarshalAs(UnmanagedType.Struct)] ref IntegerState operand);

        [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "__gmpz_probab_prime_p", ExactSpelling = true)]
        public static extern int IsProbablePrime(
            [In, Out, MarshalAs(UnmanagedType.Struct)] ref IntegerState operand,
            [In, MarshalAs(UnmanagedType.I2)] short tests);

        [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "__gmpz_lcm", ExactSpelling = true)]
        public static extern void LCM(
            [In, Out, MarshalAs(UnmanagedType.Struct)] ref IntegerState result,
            [In, MarshalAs(UnmanagedType.Struct)] ref IntegerState first,
            [In, MarshalAs(UnmanagedType.Struct)] ref IntegerState second);

        #endregion

        #region Comparison

        [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "__gmpz_cmp", ExactSpelling = true)]
        public static extern int Compare(
            [In, MarshalAs(UnmanagedType.Struct)] ref IntegerState first,
            [In, MarshalAs(UnmanagedType.Struct)] ref IntegerState second);

        #endregion

        #region Bitwise

        [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "__gmpz_neg", ExactSpelling = true)]
        public static extern void Negate(
            [In, Out, MarshalAs(UnmanagedType.Struct)] ref IntegerState result,
            [In, MarshalAs(UnmanagedType.Struct)] ref IntegerState operand);

        [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "__gmpz_and", ExactSpelling = true)]
        public static extern void And(
            [In, Out, MarshalAs(UnmanagedType.Struct)] ref IntegerState result,
            [In, MarshalAs(UnmanagedType.Struct)] ref IntegerState first,
            [In, MarshalAs(UnmanagedType.Struct)] ref IntegerState second);

        [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "__gmpz_ior", ExactSpelling = true)]
        public static extern void InclusiveOr(
            [In, Out, MarshalAs(UnmanagedType.Struct)] ref IntegerState result,
            [In, MarshalAs(UnmanagedType.Struct)] ref IntegerState first,
            [In, MarshalAs(UnmanagedType.Struct)] ref IntegerState second);

        [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "__gmpz_xor", ExactSpelling = true)]
        public static extern void ExclusiveOr(
            [In, Out, MarshalAs(UnmanagedType.Struct)] ref IntegerState result,
            [In, MarshalAs(UnmanagedType.Struct)] ref IntegerState first,
            [In, MarshalAs(UnmanagedType.Struct)] ref IntegerState second);

        [CLSCompliant(false)]
        [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "__gmpz_mul_2exp", ExactSpelling = true)]
        public static extern void ShiftLeft(
            [In, Out, MarshalAs(UnmanagedType.Struct)] ref IntegerState result,
            [In, MarshalAs(UnmanagedType.Struct)] ref IntegerState operand,
            [In, MarshalAs(UnmanagedType.U4)] uint count);

        [CLSCompliant(false)]
        [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "__gmpz_tdiv_q_2exp", ExactSpelling = true)]
        public static extern void ShiftRight(
            [In, Out, MarshalAs(UnmanagedType.Struct)] ref IntegerState result,
            [In, MarshalAs(UnmanagedType.Struct)] ref IntegerState operand,
            [In, MarshalAs(UnmanagedType.U4)] uint count);

        [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "__gmpz_com", ExactSpelling = true)]
        public static extern void Complement(
            [In, Out, MarshalAs(UnmanagedType.Struct)] ref IntegerState result,
            [In, MarshalAs(UnmanagedType.Struct)] ref IntegerState operand);

        #endregion

        #region Miscellaneous

        [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "__gmpz_odd_p", ExactSpelling = true)]
        public static extern int IsOdd(
            [In, MarshalAs(UnmanagedType.Struct)] ref IntegerState operand);

        [DllImport(LibraryName,  CallingConvention = CallingConvention.Cdecl, EntryPoint = "__gmpz_sizeinbase", ExactSpelling = true)]
        public static extern int GetSize(
            [In, MarshalAs(UnmanagedType.Struct)] ref IntegerState operand,
            [In, MarshalAs(UnmanagedType.I4)] int radix);

        #endregion
    }
}